简介

java nio 是jdk1.4引入的,其中包含 selector,channel,buffer 其中buffer是用来提高效率的。nio中操作数据,都是直接操作buffer对象

buffer的类型

  • ByteBuffer
  • CharBuffer
  • ShortBuffer
  • IntBuffer
  • LongBuffer
  • FloatBuffer
  • DoubleBuffer

java基本类型除了boolean外都有对应的buffer的对象,都是使用allocate()方法创建对应的buffer对象

Buffer 的相关属性

  • capacity 容量
    用来定义buffer的容量,在buffer初始化的时候设置,不可被修改
  • limit 界限
  • buffer的上限位置,limit <= capacity
  • pasition 位置
  • 读写buffer的时候,下一个写或者读的位置 pasition小于 limit
  • mark 标记位置
  • 使用mark()方法标记的位置,当调用reset()方法时,将pasition指向mark的位置

buffer 初始化

buffer 初始化调用 allocate()方法创建,下面看一下源码

1
2
3
4
5
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}

可以看到 使用 new HeapByteBuffer(capacity, capacity); 在jvm堆中创建一个buffer对象

1
2
3
4
5
6
7
8
9
10
11
12
Buffer(int mark, int pos, int lim, int cap) {
if (cap < 0)
throw new IllegalArgumentException("Negative capacity: " + cap);
this.capacity = cap;
limit(lim);
position(pos);
if (mark >= 0) {
if (mark > pos)
throw new IllegalArgumentException("mark > position: ("+ mark + " > " + pos +")");
this.mark = mark;
}
}

当初始化Bytebuffer后实际的buffer对象的相关属性情况如下。

image.png

Buffer的核心方法

  • get()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public byte get() {
    return hb[ix(nextGetIndex())];
    }

    final int nextGetIndex() {
    if (position >= limit)
    throw new BufferUnderflowException();
    return position++;
    }
  • put()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public ByteBuffer put(byte x) {
    hb[ix(nextPutIndex())] = x;
    return this;
    }

    final int nextPutIndex() {
    if (position >= limit)
    throw new BufferOverflowException();
    return position++;
    }
    比如put a,b,c,d 到buffer中实际的存储情况是这样的
    image.png
    每次put的时候position 都指向后一位
  • flip()
    上图我们将a,b,c,d 加入到buffer后。当我们调用get()方法的时候是获取不到数据的,因为position是5调用get方法获取不到数据。
    所以我们想获取数据,需要将position重新设置为0
    查看get()源码,我们发现position >= limit才会抛出异常。所以我们还需要设置limit到5,需要两部操作。而flip()方法是将上面两个操作和成一个方法。执行的结果如下
    image.png
  • Rewind()
    我们指向将position恢复到0,不影响limit,可以调用这个方法。
  • Clear()
    调用clear方法,会将position设置到0,limit设置到capatity
    在数组中真是的数据是没有被删除的。后续的put操作会覆盖原来的数据。
  • Mark()
    标记,表示记录到当前position 的位置可以通过reset()恢复到mark()标记位置
  • hasremaining()
    判断缓冲区中是否还有剩余数据
  • Remaining()
    获取缓冲区还可以操作的数据